package com.ask.javabagubooster.b_spring_framework.aop.aspect;

import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Arrays;

@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* com.ask.javabagubooster.b_spring_framework.aop.demo.*.*(..))")
    private void apiLogPointcut1() {}

    @Pointcut("@annotation(com.ask.javabagubooster.b_spring_framework.aop.annotation.ApiLog)")
    private void apiLogPointcut2() {}

    @Before("apiLogPointcut1()") // 组合两个切点表达式，只要满足其中一个就会执行增强逻辑
    public void beforeAdvice() {
        System.out.println("Before method execution");
    }

    // 4. 定义环绕通知，功能最强大
    @Around("apiLogPointcut2()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 获取HTTP请求信息（在Web环境中）
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 打印请求前日志
        System.out.println("=============== AOP Log Start ===============");
        System.out.println("请求URL   : " + request.getRequestURL().toString());
        System.out.println("请求方式  : " + request.getMethod());
        System.out.println("IP 地址   : " + request.getRemoteAddr());
        // 获取方法签名，可以拿到方法名、类名等
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        System.out.println("目标方法  : " + signature.getDeclaringTypeName() + "." + signature.getName());
        System.out.println("请求参数  : " + Arrays.toString(joinPoint.getArgs()));
        Object result;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Throwable t) {
            // 发生异常
            long endTime = System.currentTimeMillis();
            System.out.println("执行耗时  : " + (endTime - startTime) + " ms");
            System.out.println("方法异常  : " + t.getMessage());
            System.out.println("=============== AOP Log Error ================");
            throw t; // 别忘了把异常抛出去
        }
        // 打印返回后日志
        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时  : " + (endTime - startTime) + " ms");
        System.out.println("返回结果  : " + result);
        System.out.println("=============== AOP Log End ==================");

        return result;
    }
}